/********************************************************************

Write Date: 2015/04/20
Author: Apple
>>>> Rename class OOPPtrHelper to ObjectRefCountHandler and move to 
     a new file.

Modify Date: 2015/04/21
Author: Apple
>>>> Modify the document.

Modify Date: 2015/04/22
Author: Apple
>>>> Rename ObjectRefCountHandler to ObjectRef and move the reference count 
     management from Ptr to it.

Modify Date: 2015/04/26
Author: Apple
>>>> Move cvt() from class Ptr to class ObjectRef
>>>> Mark ObjectRef (), ObjectRef (ObjectRef&), ObjectRef (ObjectRef&&), 
     operator= (ObjectRef&), operator= (ObjectRef&&) as public.
>>>> Add const to the paremeter of copy constructor and copy assignment.

Modify Date: 2015/05/05
Author: Apple
>>>> Fix the bug: Cannot release the data in the Wrapper.

Modify Date: 2015/05/07
Author: Apple
>>>> Correct the code of type determination in cvt().
>>>> Add function isNull().
>>>> Add const version of cvt().
>>>> Add const qualifier to functions needed.
>>>> Complete the document.

Modify Date: 2015/08/12
Author: Apple
>>>> Remove function isNull().
>>>> Move operator== from Ptr to here.
>>>> Add operator!=.
>>>> Fix the wrong placement of _NS_OOP_BEGIN in ObjectRef.hpp.

Modify Date: 2015/08/17
Author: Apple
>>>> Remove the condition term about Object::_isOnHeap in __shouldRelease().

*********************************************************************/
#pragma once
#include "Object.h"



_NS_OOP_BEGIN



/**
 * Class ObjectRef provides the function to manage the reference 
 * count of an Object. Class Ptr< T > are inherited from it.
 *
 * Thread-Safe: yes
 *
 * @remarks 2015/04/20, Apple
 */
class ObjectRef
{
public:

	/**
	 * Create an ObjectRef pointing to NULL.
	 */
	ObjectRef ();

	/**
	 * Destroy a ObjectRef. If the reference count of the target is down to zero, 
	 * destroy the target.
	 */
	virtual ~ObjectRef ();

	/**
	 * Create an ObjectRef pointing to the target of another ObjectRef
	 *
	 * @param r_right - the source ObjectRef
	 */
	ObjectRef (const ObjectRef& r_right);

	/**
	 * Create an ObjectRef and move the target of another ObjectRef to it. 
	 * This will set the target of source ObjectRef to NULL.
	 *
	 * @param rr_right - the source ObjectRef
	 */
	ObjectRef (ObjectRef&& rr_right);

	/**
	 * Set the target to the target of another ObjectRef.
	 *
	 * @param r_right - the source ObjectRef
	 * @return *this
	 */
	ObjectRef& operator= (const ObjectRef& r_right);

	/**
	 * Move the target of another ObjectRef to this. This will set the target of
	 * source ObjectRef to NULL.
	 *
	 * @param rr_right - the source ObjectRef
	 * @return *this
	 */
	ObjectRef& operator= (ObjectRef&& rr_right);

	/**
	 * Set the target to NULL. The reference count of original target will be 
	 * decreased by one and if it is down to zero, the original target will be 
	 * destroied.
	 */
	void setNull ();

	/**
	 * Cast the target's type. Dynamic cast check will be processed if the 
	 * target and T are both inherited from Object. If only one of the target \
	 * and T is inherited from Object, cast failed. If none, a explicit cast is 
	 * processed and the correction is not guaranteed.
	 *
	 * @return a Ptr pointing to the target with type T
	 * @throw TypeConvertFailException - If cast failed
	 */
	template< class T >
	Ptr< T > cvt () throw (TypeConvertFailException);
	template< class T >
	const Ptr< T > cvt () const throw (TypeConvertFailException);

	/**
	* Check whether an ObjectRef points to the same target as this.
	*
	* @param ptr - an ObjectRef to check
	* @return whether an ObjectRef points to the same target as this
	*/
	bool operator== (const ObjectRef& r_ref) const;

	/**
	* Check whether a raw pointer points to the same target as this.
	*
	* @param ptr - a raw pointer to check
	* @return whether a raw pointer points to the same target as this
	*/
	bool operator== (void* ptr) const;

	/**
	* Check whether an ObjectRef does NOT point to the same target as this.
	*
	* @param ptr - an ObjectRef to check
	* @return whether an ObjectRef does NOT point to the same target as this
	*/
	bool operator!= (const ObjectRef& r_ref) const;

	/**
	* Check whether a raw pointer does NOT point to the same target as this.
	*
	* @param ptr - a raw pointer to check
	* @return whether a raw pointer does NOT point to the same target as this
	*/
	bool operator!= (void* ptr) const;

protected:

	/* The reference target */
	Object* __p_obj;

	/**
	 * Create an ObjectRef pointing to an Object.
	 *
	 * @param p_obj - the target
	 */
	ObjectRef (Object* p_obj);

	/**
	 * Increase the reference count of an object by one.
	 *
	 * @param p_obj - the Object to increase the reference count
	 */
	void __incrRef ();

	/**
	 * Decrease the reference count of an object by one.
	 *
	 * @param p_obj - the Object to decrease the reference count
	 */
	void __decrRef ();

	/**
	 * Get the reference count.
	 *
	 * @return the reference count
	 */
	int __getRef () const;

	/**
	 * Check wheter the target should be released.
	 *
	 * @return wheter the target should be released
	 */
	bool __shouldRelease () const;

	/**
	 * Try to release an object if its reference count is zero.
	 *
	 * @param p_obj - the Object to try release
	 */
	void __tryRelease ();

	/**
	 * Release the target. Override it in child class to release custom data.
	 */
	virtual void __release ();

};



_NS_OOP_END



#include "ObjectRef.hpp"